package org.tomac.fix.example.fix42nordic;

import java.io.IOException;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.tomac.io.IIOPlexor;
import org.tomac.io.ITimerTask;
import org.tomac.io.fix.FixAcceptor;
import org.tomac.io.fix.FixURL;
import org.tomac.io.fix.IFixApplication;
import org.tomac.io.fix.IFixSession;
import org.tomac.io.fix.IFixURL;
import org.tomac.io.nio.NIOPlexorTest;
import org.tomac.protocol.fix.messaging.FixHeartbeat;
import org.tomac.protocol.fix.messaging.FixLogon;
import org.tomac.protocol.fix.messaging.FixLogout;
import org.tomac.protocol.fix.messaging.FixMessage;
import org.tomac.protocol.fix.messaging.FixMessageListener;
import org.tomac.protocol.fix.messaging.FixMessageListenerImpl;
import org.tomac.protocol.fix.messaging.FixNewOrderSingle;
import org.tomac.protocol.fix.messaging.FixReject;
import org.tomac.protocol.fix.messaging.FixResendRequest;
import org.tomac.protocol.fix.messaging.FixSequenceReset;
import org.tomac.protocol.fix.messaging.FixTestRequest;

public class FixServer extends FixMessageListenerImpl implements IFixApplication, FixMessageListener {

	private static Logger log = Logger.getLogger(FixServer.class.getSimpleName());
	
	FixMessageListenerReplicator replicator = new FixMessageListenerReplicator(this);
	FixMessageListener fixSessionInboundFixMessageListener;
	FixAcceptor session;
	NIOPlexorTest mux;
	IFixURL url;
	final int RECONNECT_TIME = 1000;
	
	static public void main(String[] args) throws InterruptedException {
		FixServer app;

		if (args.length < 1) {
			System.out.println("Usage: FixServer <fix_url>");
			System.out.println("Example: FixServer fix42nordic://TE:TOMAC@127.0.0.1:1212/?heartBtInt=60#acceptor");
			return;
		}

		BasicConfigurator.configure();

		app = new FixServer();

		try {
			app.mux = new NIOPlexorTest();
		} catch (IOException e) {
			if (log.isDebugEnabled()) log.error(e.getMessage(), e);
			else log.error(e.getMessage());
			return;
		}
		app.url = new FixURL(args[0]); // the static configuration
		//application = ...;
		app.session = new FixAcceptor(app.mux, app.url, app);

		try {
			app.session.connect();
		} catch (IOException e) {
			if (log.isDebugEnabled()) log.error(e.getMessage(), e);
			else log.error(e.getMessage());
			return;
		}
		
		// either starta a thread or I run it in main
		app.mux.run();
		
	}

	@Override
	public void init(IFixSession session, IIOPlexor plex) {
		// TODO Auto-generated method stub
		
	}
	
	@Override
	public void onDisconnect() {
		log.info("Got disconnect");
		ReconnectTimerTask reconn = new ReconnectTimerTask(mux, session, RECONNECT_TIME);
		mux.scheduleTimer(reconn, RECONNECT_TIME);
	}

	@Override
	public void onConnect() {
		log.info("Got connect");
	}
	
	@Override
	public FixMessageListener getInboundFixMessageReplicator() {
		return replicator;
	}

	@Override
	public void onFixNewOrderSingle(FixNewOrderSingle msg) {
		msg.buf.flip();
		byte[] buf = new byte[msg.buf.limit()];
		msg.buf.slice().get(buf);
		if (log.isDebugEnabled()) log.debug("Bounce NewOrderSingle: " + new String(buf).replace("\1", "@"));
		session.send(msg);
	}
	
	private class FixMessageListenerReplicator extends FixMessageListenerImpl implements FixMessageListener {
		
		FixServer parent;
		
		public FixMessageListenerReplicator(FixServer fixApplicationTest) {
			parent = fixApplicationTest;
		}

		@Override
		public void onFixNewOrderSingle(FixNewOrderSingle msg) {
			fixSessionInboundFixMessageListener.onFixNewOrderSingle(msg); // increment InSeqNo
			parent.onFixNewOrderSingle(msg);
		}

		@Override
		public void onUnknownMessageType(FixMessage msg) {
			fixSessionInboundFixMessageListener.onUnknownMessageType(msg);
		}

		@Override
		public void onFixHeartbeat(FixHeartbeat msg) {
			fixSessionInboundFixMessageListener.onFixHeartbeat(msg);
			
		}

		@Override
		public void onFixLogon(FixLogon msg) {
			fixSessionInboundFixMessageListener.onFixLogon(msg);
			
		}

		@Override
		public void onFixLogout(FixLogout msg) {
			fixSessionInboundFixMessageListener.onFixLogout(msg);
			
		}

		@Override
		public void onFixReject(FixReject msg) {
			fixSessionInboundFixMessageListener.onFixReject(msg);
			
		}

		@Override
		public void onFixResendRequest(FixResendRequest msg) {
			fixSessionInboundFixMessageListener.onFixResendRequest(msg);
			
		}

		@Override
		public void onFixSequenceReset(FixSequenceReset msg) {
			fixSessionInboundFixMessageListener.onFixSequenceReset(msg);
			
		}

		@Override
		public void onFixTestRequest(FixTestRequest msg) {
			fixSessionInboundFixMessageListener.onFixTestRequest(msg);
			
		}
	}
	
	public class FixAcceptorTest extends org.tomac.io.fix.FixAcceptor {

		public FixAcceptorTest(IIOPlexor plex, IFixURL url, IFixApplication application) {
			super(plex, url, application);
		}

		@Override
		public void onFixNewOrderSingle(FixNewOrderSingle msg) {
			incrementInMsgSeqNum();
		}
		

	}	

	private class ReconnectTimerTask implements ITimerTask {
		IFixSession session;
		int previousTime;
		NIOPlexorTest mux;

		public ReconnectTimerTask(NIOPlexorTest mux, IFixSession session, int previousTime) {
			this.session = session;
			this.previousTime = previousTime;
			this.mux = mux;
		}

		@Override
		public void run() {
			try {
				session.connect();
			} catch (IOException e) {
				if (log.isDebugEnabled()) log.error(e.getMessage(), e);
				else log.error(e.getMessage());
				mux.scheduleTimer(this, previousTime * 2);
			}
		}
		
	}
	
	
}
